#pragma once
#include<iostream>
#include<assert.h>
using std::endl;
using std::cout;

namespace Mango
{
class string
{
public:

	//////////////////////////////构造,析构,拷贝构造,赋值重载,移动构造,移动赋值/////////////////////////////////////////
	
	//坑点:初始化列表的初始化顺序是 成员的声明顺序 而不是 在初始化列表当中的书写顺序
	string(const char* str = "") :_size(strlen(str)),_capacity(_size)
	{
		_str = new char[_capacity + 1];
		strcpy(_str, str);
	}
	
	string(const string& str) :_size(str._size),_capacity(str._capacity)
	{
		_str = new char[_capacity + 1];
		strcpy(_str, str._str);
	}

	//现代写法
	//此处_str必须初始化为空,否则就是野指针,交换之后,最后释放tmp对象,会释放_str指向的空间,如果是野指针就会导致错误
	/*string(const string& str) :_str(nullptr) 
	{
		string tmp(str._str);
		swap(tmp);
	}*/

	string& operator=(const string& str)
	{
		if(this != &str)
		{
			char* tmp = new char[str._capacity + 1];
			if (tmp != nullptr)
			{
				strcpy(tmp, str._str);
				delete[] _str;

				_str = tmp;
				_size = str._size;
				_capacity = str._capacity;
			}
			else
			{
				//如果新空间开辟失败,那么认为赋值失败
				cout << "new space fail ---operator=()" << "\n";
			}
		}
		return *this;
	}
	
	//现代写法
	//string& operator=(const string& str)
	//{
	//	if (this != &str)
	//	{
	//		string tmp(str._str);//构造一个临时对象
	//		swap(tmp);
	//	}
	//	return *this;
	//}

	string(string&& str) :_str(nullptr)
	{
		swap(str);
	}

	string& operator=(string&& str)
	{
		if (this != &str)
		{
			swap(str);
		}
		return *this;
	}

	template<class T>
	void swap(T&& str) //万能引用
	{
		//由于没有进行展开std命名空间 所以不可以直接::swap,需要指明命名空间
		std::swap(_str,str._str);
		std::swap(_size, str._size);
		std::swap(_capacity, str._capacity);
	}

	~string()
	{
		if (_str != nullptr)
			delete[] _str;
		
		_str = nullptr;//防止野指针
		_size = _capacity = 0;
	}


	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//  ///////////////////////////迭代器相关  /// ///////////////////////////
	typedef char* iterator;
	typedef const char* const_iterator;

	iterator begin()
	{
		return _str;
	}
	iterator end()
	{
		return _str + _size;
	}

	const_iterator begin() const
	{
		return _str;
	}
	const_iterator end() const
	{
		return _str + _size;
	}
// ///////////////////////////迭代器相关  /// ///////////////////////////

//////////////////////////////////////////////////  朴素的小函数/////////////////
	size_t size() const
	{
		return _size;
	}
	size_t capacity() const
	{
		return _capacity;
	}
	bool empty() const
	{
		return _str == nullptr;
	}
	void clear() 
	{
		_str[0] = '\0';
		_size = 0;
	}

	char& operator[](size_t pos)
	{
		assert(pos < _size);
		return _str[pos];
	}

	const char& operator[](size_t pos) const
	{
		assert(pos < _size);
		return _str[pos];
	}

////////////////////容量相关函数//////////////////////////////////////////////////////////

	void reserve(int n)
	{
		if (n > capacity()) //扩容
		{
			char* tmp = new char[n+1];//多开一个空间存\0
			if (tmp != nullptr)
			{
				//注意：如果有效字符为\0,那么就会导致拷贝少了  例如:_str:hel\0l0\0 
				//所以尽量不要使用strcpy，而是使用strncpy
				strncpy(tmp, _str,_size+1); //\0也要拷贝 
				delete[] _str;

				_str = tmp;
				_capacity = n;
			}
		}
	}


	void resize(int n,char ch = '\0')
	{
		if (n < size()) //减少元素个数
		{
			_str[n] = '\0';
			_size = n;
		}
		else
		{
			if (n > capacity())
				reserve(n);

			for (int i = _size; i < n; i++)
				_str[i] = ch;

			_size = n;
			_str[_size] = '\0';
		}
	}
	const char* c_str() const
	{
		return _str;
	}
//////////////////////////////////////////////////////////////////////////////

	///////////////////////////增删查改///////////////////////////////////////////////////
	void push_back(char ch)
	{
		if (size() == capacity())
			reserve(capacity() == 0 ? 4 : capacity() * 2);

		_str[_size++] = ch;
		_str[_size] = '\0';
	}
	void append(const char* str)
	{
		int len = strlen(str);
		int totalSize = _size + len;
		if (totalSize > _capacity)
		{
			reserve(totalSize);
		}
		strncpy(_str + _size, str, strlen(str));
		_size = totalSize;
		_str[_size] = '\0';
	}
	string& operator+=(const char* str)
	{
		append(str);
		return *this;
	}
	string& operator+=(const char ch)
	{
		push_back(ch);
		return *this;
	}
	string& insert(size_t pos, const char* str)
	{
		assert(pos <= _size);
		int len = strlen(str);
		int totalSize =  len + _size;
		if (totalSize > capacity())
		{
			reserve(totalSize);
		}
		//将pos往后的所有内容,往后移动len个长度
		char* end = _str + _size;
		while (end >= _str + pos)
		{
			*(end + len) = *end; //将end位置的字符往后移动len个单位
			end--;
		}
		//在pos位置插入字符串str
		strncpy(_str + pos, str, len);

		_size = totalSize; //记得更新总长度
		_str[_size] = '\0';
		return *this;

	}
	string& insert(size_t pos, char ch)
	{
		assert(pos <= _size);
		if (size() == capacity())
		{
			reserve(capacity() == 0 ? 4 : capacity() * 2);
		}
		/*
		//死循环写法：如果pos为0，因为size_t类型为无符号类型,恒>=0，所以会导致死循环
		size_t end = _size - 1;
		while (end >= pos)
		{
			_str[end + 1] = _str[end];
			end--;
		}
		*/

		char* end = _str + _size - 1;
		while (end >= _str + pos)
		{
			*(end + 1) = *end;
			end--;
		}
		_size++;//有效元素个数++
		_str[pos] = ch;
		return *this;
	}
	string& erase(size_t pos, size_t len = npos)
	{
		assert(pos < _size); //_size位置放的是\0,不能删除该位置的元素
		int SurplusEle = _size - pos;//pos之后还有多少个元素
		//len:从pos往后删除len个字符
		if (len >= SurplusEle) //说明pos往后的字符都不要了
		{
			_str[pos] = '\0';
			_size = pos;
		}
		else
		{
			//将pos+len后面的字符替换到pos位置
			strcpy(_str + pos, _str + pos + len);
			//注意：需要减少有效元素个数
			_size -= len;
		}
	}
	//////////////////////////////////////////////////////////////////////////////
private:
	char* _str;
	size_t _size;
	size_t _capacity;
	static size_t npos;
};
size_t string::npos = -1;
}
